#include "SceneEngine.h"
#include "VGPLib.h"
#include <iostream>

using namespace cocos2d;
SceneEngine* SceneEngine::instance;

extern CCSpriteFrameCache* s_spriteFrameCache;

extern int s_language;

SceneEngine::SceneEngine()
{
	this->objectArray = new CCArray();
	this->buttonArray = new CCArray();
	this->stringArray = new CCArray();	
	this->progressTimerArray = new CCArray();
}

SceneEngine::~SceneEngine()
{
	this->objectArray->release();
	this->objectArray = NULL;
	this->buttonArray->release();
	this->buttonArray = NULL;
	this->stringArray->release();
	this->stringArray = NULL;	
	this->progressTimerArray->release();
	this->progressTimerArray = NULL;	
}

SceneEngine* SceneEngine::getInstance()
{
	if ( instance == NULL )
		instance = new SceneEngine();
	return instance;
}

int SceneEngine::getElementTag( int sceneID, int elementID )
{
	return ( sceneID*GUI_MAX_ELEMENT + elementID );
}

int SceneEngine::getMaxTag( int sceneID )
{
	return ( sceneID*GUI_MAX_ELEMENT + s_guiElementMax[sceneID] );
}

int SceneEngine::getMinTag ( int sceneID )
{
	return ( sceneID*GUI_MAX_ELEMENT );
}

int SceneEngine::getElementIDFromTag ( int tag )
{
	return ( tag - ( ( tag/GUI_MAX_ELEMENT ) * GUI_MAX_ELEMENT ) );
}

void SceneEngine::getSceneElementProperties ( int sceneID, int elementID )
{
	this->sceneEngine_template = s_guiLevel[sceneID][elementID][SceneEngine::PARAM_TEMPLATE];
	this->sceneEngine_x = s_guiLevel[sceneID][elementID][SceneEngine::PARAM_X];
	this->sceneEngine_y = CCDirector::sharedDirector()->getVisibleSize().height - s_guiLevel[sceneID][elementID][SceneEngine::PARAM_Y];
	this->sceneEngine_visible = s_guiLevel[sceneID][elementID][SceneEngine::PARAM_VISIBLE];
	switch ( this->sceneEngine_template )
	{
	case GUI_TEMPLATE::SPRITEBASED:
		this->sceneEngine_spriteID = s_guiLevel[sceneID][elementID][SceneEngine::PARAM_SPRITE_ID];
		this->sceneEngine_moduleID = s_guiLevel[sceneID][elementID][SceneEngine::PARAM_MODULE_ID];
		this->sceneEngine_animID = s_guiLevel[sceneID][elementID][SceneEngine::PARAM_ANIM_ID];
		this->sceneEngine_animCount = s_guiLevel[sceneID][elementID][SceneEngine::PARAM_ANIM_COUNT];
		this->sceneEngine_delay = s_guiLevel[sceneID][elementID][SceneEngine::PARAM_DELAY];
		break;

	case GUI_TEMPLATE::SPRITEMOVE:
		this->sceneEngine_spriteID = s_guiLevel[sceneID][elementID][SceneEngine::PARAM_SPRITE_ID];
		this->sceneEngine_moduleID = s_guiLevel[sceneID][elementID][SceneEngine::PARAM_MODULE_ID];
		this->sceneEngine_des_x = s_guiLevel[sceneID][elementID][SceneEngine::PARAM_DES_X];
		this->sceneEngine_des_y = CCDirector::sharedDirector()->getVisibleSize().height - s_guiLevel[sceneID][elementID][SceneEngine::PARAM_DES_Y];
		this->sceneEngine_jump_step = s_guiLevel[sceneID][elementID][SceneEngine::PARAM_JUMP_STEP];
		break;

	case GUI_TEMPLATE::BUTTON:
		this->sceneEngine_spriteID = s_guiLevel[sceneID][elementID][SceneEngine::PARAM_SPRITE_ID];
		this->sceneEngine_moduleID = s_guiLevel[sceneID][elementID][SceneEngine::PARAM_MODULE_ID];
		this->sceneEngine_module_selectID = s_guiLevel[sceneID][elementID][SceneEngine::PARAM_MODULE_SELECT_ID];
		break;

	case GUI_TEMPLATE::STRINGBASED:
		this->sceneEngine_fontID = s_guiLevel[sceneID][elementID][SceneEngine::PARAM_FONT_ID];
		this->sceneEngine_textID = s_guiLevel[sceneID][elementID][SceneEngine::PARAM_TEXT_ID];
		this->sceneEngine_halign = s_guiLevel[sceneID][elementID][SceneEngine::PARAM_HALIGN];
		this->sceneEngine_valign = s_guiLevel[sceneID][elementID][SceneEngine::PARAM_VALIGN];
		break;	

	case GUI_TEMPLATE::STRINGRECT:
		this->sceneEngine_fontID = s_guiLevel[sceneID][elementID][SceneEngine::PARAM_FONT_ID];
		this->sceneEngine_textID = s_guiLevel[sceneID][elementID][SceneEngine::PARAM_TEXT_ID];
		this->sceneEngine_halign = s_guiLevel[sceneID][elementID][SceneEngine::PARAM_HALIGN];
		this->sceneEngine_valign = s_guiLevel[sceneID][elementID][SceneEngine::PARAM_VALIGN];
		this->sceneEngine_rect_w = s_guiLevel[sceneID][elementID][SceneEngine::PARAM_RECT_W];
		this->sceneEngine_rect_h = s_guiLevel[sceneID][elementID][SceneEngine::PARAM_RECT_H];
		break;	
	case GUI_TEMPLATE::RECT:		
		this->sceneEngine_rect_w = s_guiLevel[sceneID][elementID][SceneEngine::PARAM_W];
		this->sceneEngine_rect_h = s_guiLevel[sceneID][elementID][SceneEngine::PARAM_H];
		this->sceneEngine_y = CCDirector::sharedDirector()->getVisibleSize().height - ( s_guiLevel[sceneID][elementID][SceneEngine::PARAM_Y] + this->sceneEngine_rect_h );
		break;	
	case GUI_TEMPLATE::PROGRESSTIMER:	
		this->sceneEngine_spriteID = s_guiLevel[sceneID][elementID][SceneEngine::PARAM_SPRITE_ID];
		this->sceneEngine_moduleID = s_guiLevel[sceneID][elementID][SceneEngine::PARAM_MODULE_ID];
		this->sceneEngine_up_down = s_guiLevel[sceneID][elementID][SceneEngine::PARAM_UP_DOWN];
		this->sceneEngine_direction = s_guiLevel[sceneID][elementID][SceneEngine::PARAM_DIRECTION];
		break;	
	}
}

CCPoint SceneEngine::getElementPosition ( int sceneID, int elementID )
{
	getSceneElementProperties ( sceneID, elementID );
	return CCPoint ( this->sceneEngine_x, this->sceneEngine_y );
}

cocos2d::CCSize SceneEngine::getElementSize ( int sceneID, int elementID )
{
	getSceneElementProperties ( sceneID, elementID );
	return CCSize ( this->sceneEngine_rect_w, this->sceneEngine_rect_h );
}

void SceneEngine::openElementScene( cocos2d::CCLayer* layer, int sceneID, int elementID )
{
	int tag = 0;	
	tag = getElementTag( sceneID, elementID );
	getSceneElementProperties( sceneID, elementID );
	switch ( this->sceneEngine_template )
	{
	case GUI_TEMPLATE::SPRITEBASED:
		if ( this->sceneEngine_moduleID != -1 ) //run frame
		{
			CCSprite* sprite = VGPSprite::getInstance()->createFrame ( this->sceneEngine_spriteID, this->sceneEngine_moduleID, CCPoint( this->sceneEngine_x, this->sceneEngine_y ), tag, tag );
			sprite->setVisible( this->sceneEngine_visible );
			layer->addChild( sprite );
			this->objectArray->addObject( sprite );
		}
		else //run anim
		{
			CCSprite* sprite;
			if ( this->sceneEngine_delay == 0 ) //defaut = 0: update each frame
				sprite = VGPSprite::getInstance()->createAnimation ( this->sceneEngine_spriteID, this->sceneEngine_animID , FRAME_TIME, this->sceneEngine_animCount, CCPoint( this->sceneEngine_x, this->sceneEngine_y ), tag, tag );
			else	
				sprite = VGPSprite::getInstance()->createAnimation ( this->sceneEngine_spriteID, this->sceneEngine_animID , this->sceneEngine_delay/1000.0f, this->sceneEngine_animCount, CCPoint( this->sceneEngine_x, this->sceneEngine_y ), tag, tag );
			sprite->setVisible( this->sceneEngine_visible );
			layer->addChild( sprite );
			this->objectArray->addObject( sprite );
		}
		break;

	case GUI_TEMPLATE::SPRITEMOVE:
		{
			CCSprite* sprite = VGPSprite::getInstance()->createFrameMove ( this->sceneEngine_spriteID, this->sceneEngine_moduleID, CCPoint( this->sceneEngine_x, this->sceneEngine_y ), CCPoint( this->sceneEngine_des_x, this->sceneEngine_des_y ), this->sceneEngine_jump_step, tag, tag );
			sprite->setVisible( this->sceneEngine_visible );
			layer->addChild( sprite );
			this->objectArray->addObject( sprite );
		}
		break;

	case GUI_TEMPLATE::BUTTON:
		{

			CCMenuItemSprite* button = VGPSprite::getInstance()->createButton( this->sceneEngine_spriteID, this->sceneEngine_moduleID, this->sceneEngine_module_selectID, CCPoint( this->sceneEngine_x, this->sceneEngine_y ), tag, tag );
			button->setVisible( this->sceneEngine_visible );

			CCMenu* menu = CCMenu::create();			
			menu->addChild( button );			
			menu->setPosition( CCPoint( 0, 0 ) );
			layer->addChild( menu , tag, tag);

			this->buttonArray->addObject( button );			
		}
		break;
	case GUI_TEMPLATE::STRINGBASED:
		{
			int x = this->sceneEngine_x;
			CCLabelBMFont* label = VGPLabel::getInstance()->createLabelBMFont( this->sceneEngine_textID, s_fontFNTList[this->sceneEngine_fontID],
				kCCLabelAutomaticWidth, CCPoint(this->sceneEngine_x, this->sceneEngine_y ), (CCTextAlignment) this->sceneEngine_halign, CCPoint( 0, 0 ), tag, tag );
			if ( this->sceneEngine_halign  == kCCTextAlignmentLeft )
			{
				x += label->getContentSize().width/2;
			}
			else if ( this->sceneEngine_halign  == kCCTextAlignmentRight )
			{
				x -= label->getContentSize().width/2;
			}	
			label->setPositionX ( x );
			label->setVisible( this->sceneEngine_visible );
			layer->addChild( label );
			this->stringArray->addObject( label );
		}
		break;
	case GUI_TEMPLATE::STRINGRECT:
		{
			CCLabelBMFont* label = VGPLabel::getInstance()->createLabelBMFont( this->sceneEngine_textID, s_fontFNTList[this->sceneEngine_fontID],
				this->sceneEngine_rect_w, CCPoint( this->sceneEngine_x, this->sceneEngine_y ), (CCTextAlignment) this->sceneEngine_halign, CCPoint( 0, 0 ), tag, tag );

			int x = this->sceneEngine_x;
			int y = this->sceneEngine_y;
			int content_w = label->getContentSize().width;
			int content_h = label->getContentSize().height;
			//horizontal
			if ( this->sceneEngine_halign  == kCCTextAlignmentLeft )
			{
				x += content_w/2;					
			}
			else if ( this->sceneEngine_halign  == kCCTextAlignmentRight )
			{
				x = x + this->sceneEngine_rect_w - label->getContentSize().width/2;
			}	
			else if ( this->sceneEngine_halign  == kCCTextAlignmentCenter )
			{
				x += this->sceneEngine_rect_w/2;
			}

			//vertical
			if ( this->sceneEngine_valign  == kCCVerticalTextAlignmentTop )
			{					
				y -= content_h/2;
			}
			else if ( (CCVerticalTextAlignment)this->sceneEngine_valign  == kCCVerticalTextAlignmentBottom )
			{					
				y = y - this->sceneEngine_rect_h + content_h/2;
			}
			else if ( (CCVerticalTextAlignment)this->sceneEngine_valign  == kCCVerticalTextAlignmentCenter )
			{					
				y -= this->sceneEngine_rect_h/2;
			}	
			label->setPosition ( CCPoint ( x, y ) );
			label->setVisible( this->sceneEngine_visible );
			layer->addChild( label );
			this->stringArray->addObject( label );
		}
		break;

	case GUI_TEMPLATE::PROGRESSTIMER:
		{
			CCSprite* sprite = VGPSprite::getInstance()->createFrame ( this->sceneEngine_spriteID, this->sceneEngine_moduleID, CCPoint( this->sceneEngine_x, this->sceneEngine_y ) );
			CCProgressTimer* progressTimer = CCProgressTimer::create( sprite );    
			progressTimer->setType(kCCProgressTimerTypeBar);

			if ( this->sceneEngine_direction )
				progressTimer->setMidpoint( CCPoint( 1, 0 ) ); 
			else
				progressTimer->setMidpoint( CCPoint( 0, 1 ) ); 

			if ( this->sceneEngine_up_down )
				progressTimer->setBarChangeRate( CCPoint( 0, 1 ) ); //   (1, 0) -> left <-> right  (0, 1) -> up <-> down
			else
				progressTimer->setBarChangeRate( CCPoint( 1, 0 ) ); //   (1, 0) -> left <-> right  (0, 1) -> up <-> down

			progressTimer->setPercentage(100);

			progressTimer->setPosition( CCPoint( this->sceneEngine_x, this->sceneEngine_y ) );

			progressTimer->setTag( tag );
			progressTimer->setZOrder ( tag );
			layer->addChild( progressTimer );
			this->progressTimerArray->addObject ( progressTimer );
		}
		break;
	}	
}

void SceneEngine::openScene( cocos2d::CCLayer* layer, int sceneID, bool removeAlLastScene )
{
	if ( removeAlLastScene )
		closeScene();

	for ( int id = 0; id < s_guiElementMax[sceneID]; id ++ )
	{
		openElementScene( layer, sceneID, id );
	}	
}

void SceneEngine::openScene( cocos2d::CCLayer* layer, int sceneID )
{
	openScene( layer, sceneID, true );
}

void SceneEngine::closeScene()
{
	this->objectArray->removeAllObjects();
	this->buttonArray->removeAllObjects();
	this->stringArray->removeAllObjects();
	this->progressTimerArray->removeAllObjects();
}

void SceneEngine::removeElement( cocos2d::CCLayer* layer, int sceneID, int elementID )
{
	int tag = getElementTag( sceneID, elementID );
	CCObject* object = NULL;
	CCArray* objectList;
	getSceneElementProperties( sceneID, elementID );
	//check button or another
	if ( this->sceneEngine_template == GUI_TEMPLATE::BUTTON )
	{
		objectList = this->buttonArray;		
	}	
	else if ( this->sceneEngine_template == GUI_TEMPLATE::STRINGBASED || this->sceneEngine_template == GUI_TEMPLATE::STRINGRECT )
	{
		objectList = this->stringArray;		
	}
	else if ( this->sceneEngine_template == GUI_TEMPLATE::PROGRESSTIMER )
	{
		objectList = this->progressTimerArray;		
	}	
	else
	{
		objectList = this->objectArray;		
	}
	CCARRAY_FOREACH( objectList, object )
	{
		CCNode* node = dynamic_cast< CCNode* >( object );
		if ( node->getTag() == tag )
		{
			objectList->removeObject( node );
			layer->removeChildByTag ( tag );
			break;
		}
	}
}

void SceneEngine::removeScene( cocos2d::CCLayer* layer, int sceneID )
{
	for ( int id = 0; id < s_guiElementMax[sceneID]; id ++ )
		removeElement( layer, sceneID, id );
}

void SceneEngine::setElementVisible( int sceneID, int elementID, bool visible )
{	
	int tag = getElementTag( sceneID, elementID );
	CCObject* object = NULL;
	CCArray* objectList;
	getSceneElementProperties( sceneID, elementID );
	//check button or another
	if ( this->sceneEngine_template == GUI_TEMPLATE::BUTTON )
	{
		objectList = this->buttonArray;		
	}	
	else if ( this->sceneEngine_template == GUI_TEMPLATE::STRINGBASED || this->sceneEngine_template == GUI_TEMPLATE::STRINGRECT )
	{
		objectList = this->stringArray;		
	}
	else if ( this->sceneEngine_template == GUI_TEMPLATE::PROGRESSTIMER )
	{
		objectList = this->progressTimerArray;		
	}
	else
	{
		objectList = this->objectArray;		
	}
	CCARRAY_FOREACH( objectList, object )
	{
		CCNode* node = dynamic_cast< CCNode* >( object );
		if ( node->getTag() == tag )
		{
			node->setVisible( visible );		
			break;
		}
	}
}

void SceneEngine::setElementPosition ( int sceneID, int elementID, cocos2d::CCPoint position )
{
	int tag = getElementTag( sceneID, elementID );
	CCObject* object = NULL;
	CCArray* objectList;
	getSceneElementProperties( sceneID, elementID );
	//check button or another
	if ( this->sceneEngine_template == GUI_TEMPLATE::BUTTON )
	{
		objectList = this->buttonArray;		
	}	
	else if ( this->sceneEngine_template == GUI_TEMPLATE::STRINGBASED || this->sceneEngine_template == GUI_TEMPLATE::STRINGRECT )
	{
		objectList = this->stringArray;		
	}
	else if ( this->sceneEngine_template == GUI_TEMPLATE::PROGRESSTIMER )
	{
		objectList = this->progressTimerArray;		
	}
	else
	{
		objectList = this->objectArray;		
	}
	CCARRAY_FOREACH( objectList, object )
	{
		CCNode* node = dynamic_cast< CCNode* >( object );
		if ( node->getTag() == tag )
		{
			node->setPosition( position );		
			break;
		}
	}
}

void SceneEngine::setElementString( int sceneID, int elementID, char* str )
{
	int tag = getElementTag( sceneID, elementID );
	CCObject* object = NULL;
	CCARRAY_FOREACH( this->stringArray, object )
	{
		CCLabelBMFont* item = dynamic_cast< CCLabelBMFont* >( object );
		if ( item->getTag() == tag )
		{
			item->setString ( str );
			break;
		}
	}
}

void SceneEngine::setElementString( int sceneID, int elementID, int stringID )
{
	setElementString( sceneID, elementID, s_text[stringID][s_language] );
}

void SceneEngine::setElementFont( int sceneID, int elementID, int fontID )
{
	int tag = getElementTag( sceneID, elementID );
	CCObject* object = NULL;
	CCARRAY_FOREACH( this->stringArray, object )
	{
		CCLabelBMFont* item = dynamic_cast< CCLabelBMFont* >( object );
		if ( item->getTag() == tag )
		{
			item->setFntFile( s_fontFNTList[fontID] );
			break;
		}
	}
}

void SceneEngine::setButtonEnable(  int sceneID, int elementID, bool enable )
{
	getButton( sceneID, elementID )->setEnabled ( enable );
}

void SceneEngine::setButtonEnable(  int sceneID, bool enable )
{
	CCObject* object = NULL;
	CCARRAY_FOREACH( this->buttonArray, object )
	{
		CCMenuItem* button = dynamic_cast< CCMenuItem* >( object );
		if ( button->getTag() >= getMinTag ( sceneID ) && button->getTag() <= getMaxTag ( sceneID ) ) 
		{
			button->setEnabled ( enable );
		}
	}
}

void SceneEngine::setSpriteFrame( int sceneID, int elementID, int spriteID, int frameID )
{
	int tag = getElementTag( sceneID, elementID );
	CCObject* object = NULL;
	CCArray* objectList;
	getSceneElementProperties( sceneID, elementID );
	//check button or another
	if ( this->sceneEngine_template == GUI_TEMPLATE::BUTTON )
	{
		CCARRAY_FOREACH( this->buttonArray, object )
		{
			CCMenuItemSprite* sprite = dynamic_cast< CCMenuItemSprite* >( object );
			if ( sprite->getTag() == tag )
			{
				CCNode* frame = CCSprite::createWithSpriteFrameName ( s_spriteFrame[spriteID][frameID] );
				sprite->setNormalImage( frame );
				break;
			}
		}
	}	
	else
	{
		CCARRAY_FOREACH( this->objectArray, object )
		{
			CCSprite* sprite = dynamic_cast< CCSprite* >( object );
			if ( sprite->getTag() == tag )
			{
				sprite->setDisplayFrame( s_spriteFrameCache->spriteFrameByName( s_spriteFrame[spriteID][frameID] ) );
				break;
			}
		}
	}

}

void SceneEngine::setSpriteAnim( int sceneID, int elementID, int spriteID, int animID )
{

}

void SceneEngine::setPercentProgress ( int sceneID, int elementID, int percent )
{
	int tag = getElementTag( sceneID, elementID );
	CCObject* object = NULL;
	CCARRAY_FOREACH( this->progressTimerArray, object )
	{
		CCProgressTimer* progressTimer = dynamic_cast< CCProgressTimer* >( object );
		if ( progressTimer->getTag() == tag )
		{
			progressTimer->setPercentage( percent );
			break;
		}
	}
}

cocos2d::CCMenuItem* SceneEngine::getButton ( int sceneID, int elementID )
{
	int tag = getElementTag( sceneID, elementID );
	CCObject* object = NULL;
	CCARRAY_FOREACH( this->buttonArray, object )
	{
		CCMenuItem* button = dynamic_cast< CCMenuItem* >( object );
		if ( button->getTag() == tag )
		{
			return button;
		}
	}
	return NULL;
}

cocos2d::CCObject* SceneEngine::getElementObject ( int sceneID, int elementID )
{
	int tag = getElementTag( sceneID, elementID );
	CCObject* object = NULL;
	CCArray* objectList;
	getSceneElementProperties( sceneID, elementID );
	//check button or another
	if ( this->sceneEngine_template == GUI_TEMPLATE::BUTTON )
	{
		objectList = this->buttonArray;		
	}	
	else if ( this->sceneEngine_template == GUI_TEMPLATE::STRINGBASED || this->sceneEngine_template == GUI_TEMPLATE::STRINGRECT )
	{
		objectList = this->stringArray;		
	}
	else
	{
		objectList = this->objectArray;		
	}
	CCARRAY_FOREACH( objectList, object )
	{
		CCNode* node = dynamic_cast< CCNode* >( object );
		if ( node->getTag() == tag )
		{
			return object;
		}
	}
	return NULL;
}